#ifndef _GOVT_EVENTS_HPP
#define _GOVT_EVENTS_HPP
/*******************************************************************************
 ** Government Sanctioned Espionage RPG                                       **
 ** http://www.government-sanctioned.us/                                      **
 **===========================================================================**
 ** Name: events.hpp                                                          **
 ** Description: Events for event-driven gameplay.                            **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the LICENSE file within             **
 ** this distribution or at $WIKI/display/GOVT/License-software.              **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $GAME_DIR/LICENSE.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 ** Copyright (c) 2009-2012  Barry Gian James <gian@gamingods.net>            **
 ** All rights reserved.                                                      **
 ******************************************************************************/
// Modified $Date$ by $Author$
#include <queue>
#include <vector>
#include <deque>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_ptr.hpp>
#include "common.hpp"
#include "uuid.hpp"

#define events_hpp_ID   "$Id$"

#define DEFAULT_EXPIRATION	15	// 15sec

//! The enumeration of all supported events in the game
// These can more easily be pulled directly from the game db ~gian
enum class EventType : uint64_t
{
	Unknown = 1,
	AgencyJoined,
	AgencyQuit,
	AgencyBurned,
	AgencyDemoted,
	AgencyPromoted,
	AggroDropped,
	AggroGained,
	AttackBegin,
	AttackEnd,
	CallForHelp,
	CastSpell,
	EnemyDeath,
	EmoteTarget,
	EnemyCountIncrease,
	EnemyCountDecrease,
	EnterRoom,
	Follow,
	FriendlyDeath,
	FriendlyVPLow,
	EnemyVPLow,
	ObjectRecvDamage,
	QuestOffered,
	QuestAccepted,
	QuestDeclined,
	QuestCompleted,
	QuestEvent,
	SelfConditionChange,
	SelfEvade,
	SelfLowHealth,
	SpellHit,
	TargetConditionChange,
	WeaponWielded,
	NPCDeath,
	PlayerDeath,
	ExitRoom ,
	ReputationAttacked ,
	ReputationKilled ,
	ReputationBrandished ,
	ReputationAided ,
	ReputationGaveTo,
	ReputationStoleFrom,
	ReputationIntimidated,
	ReputationThreatened,
	ReputationMisdemeanor,
	ReputationFelony,
	ReputationHarassed,
	ReputationBribed,
	WeaponUnwielded

};

//enum class EventType : uint64_t
//{
//	Unknown = 0x0000000000000000,
//	AgencyJoined = 0x0000000000000001,
//	AgencyQuit = 0x0000000000000002,
//	AgencyBurned = 0x0000000000000004,
//	AgencyDemoted = 0x0000000000000008,
//	AgencyPromoted = 0x0000000000000010,
//	AggroDropped = 0x0000000000000020,
//	AggroGained = 0x0000000000000040,
//	AttackBegin = 0x0000000000000080,
//	AttackEnd = 0x0000000000000100,
//	CallForHelp = 0x0000000000000200,
//	CastSpell = 0x0000000000000400,
//	EnemyDeath = 0x0000000000000800,
//	EmoteTarget = 0x0000000000001000,
//	EnemyCountIncrease = 0x0000000000002000,
//	EnemyCountDecrease = 0x0000000000004000,
//	EnterRoom = 0x0000000000008000,
//	Follow = 0x0000000000010000,
//	FriendlyDeath = 0x0000000000020000,
//	FriendlyVPLow = 0x0000000000040000,
//	EnemyVPLow = 0x0000000000080000,
//	ObjectRecvDamage = 0x0000000000100000,
//	QuestOffered = 0x0000000000200000,
//	QuestAccepted = 0x0000000000400000,
//	QuestDeclined = 0x0000000000800000,
//	QuestCompleted = 0x0000000001000000,
//	QuestEvent = 0x0000000002000000,
//	SelfConditionChange = 0x0000000004000000,
//	SelfEvade = 0x0000000008000000,
//	SelfLowHealth = 0x0000000010000000,
//	SpellHit = 0x0000000020000000,
//	TargetConditionChange = 0x0000000040000000,
//	WeaponWielded = 0x0000000080000000,
//	NPCDeath = 0x0000000100000000,
//	PlayerDeath = 0x0000000200000000,
//	ExitRoom = 0x0000000400000000,
//	ReputationAttacked = 0x0000000800000000,
//	ReputationKilled = 0x0000001000000000,
//	ReputationBrandished = 0x0000002000000000,
//	ReputationAided = 0x0000004000000000,
//	ReputationGaveTo = 0x0000008000000000,
//	ReputationStoleFrom = 0x0000010000000000,
//	ReputationIntimidated = 0x0000020000000000,
//	ReputationThreatened = 0x0000040000000000,
//	ReputationMisdemeanor =0x0000080000000000,
//	ReputationFelony = 0x0000100000000000,
//	ReputationHarassed = 0x0000200000000000,
//	ReputationBribed = 0x0000400000000000,
//	WeaponUnwielded = 0x0000800000000000
//
//};

enum class EventEnv { Global, Local };

//! The enumeration of all supported event triggers in the game
enum class TriggerType : unsigned short
{
	Unknown = 1,
	Command,
	Interaction,
	Proximity,
	TimeBased,
	EventBased,
	Initialization,
	SkillCheck,
	Environmental,
	Damage,
	Condition,
	Combat
};

//! @class Event
//! @brief The given event to be fired
class Event
{
public:
	SMART_PTR_DECL(Event);

	Event() { _id = global::UUIDFactory::Create(); _timestamp = boost::posix_time::second_clock::local_time(); }
	Event(const std::string & n, EventType et, TriggerType tt, entity_t src);
	virtual ~Event() {  }

	virtual void operator() (entity_t,EventType) { }

	void		Subscribe(entity_t e) { _subscribers.push_back(e); }
	void		Unsubscribe(entity_t e) {
		std::vector<entity_t>::iterator i;
		for (i = _subscribers.begin(); i != _subscribers.end(); ++i)
			if ((*i) == e)
				_subscribers.erase(i);
	}

	// Getters
	const std::string &	ID() const { return _id; }
	const std::vector<entity_t> &	Subscribers() const { return _subscribers; }
	const boost::posix_time::ptime & Interval() const { return _exeTime; }
	const boost::posix_time::ptime & Timestamp() const { return _timestamp; }
	const boost::posix_time::ptime & Expiration() const { return _expiration; }
	const std::string & Name() const { return _name; }
	const bool IsRepeating() const { return _isRepeating; }
	const boost::posix_time::ptime NextFire() const { return _nextFire; }

	// Setters
	void Name(const std::string & n) { _name = n; }
	void IsRepeating(bool r) { _isRepeating = r; }
	void Interval(boost::posix_time::ptime & p) { _exeTime = p; }
	void Expiration(boost::posix_time::ptime & e) { _expiration = e; }
	void NextFire(boost::posix_time::ptime & f) { _nextFire = f; }

protected:
	std::string	_name;
	std::string	_id;
	entity_t	_source;
	EventType	_type;
	TriggerType _trigger;
	EventEnv	_env;
	bool        _isRepeating;
	ushort      _radius;
	boost::posix_time::ptime      _exeTime;
	boost::posix_time::ptime      _timestamp;
	boost::posix_time::ptime      _expiration;
	boost::posix_time::ptime      _nextFire;
	entity_t 	_idroom;
//	Position    pos;

	// NB. This may get removed for later.
	std::vector<entity_t>	_subscribers;
};

// TimedEvent comparison functor
class TimedEventComp : public std::binary_function<Event::pointer,Event::pointer,bool>
{
public:
	bool operator() (const first_argument_type & left, const second_argument_type & right)
	{
		return left->NextFire() > right->NextFire();
	}
};

//! @class EventManager
//! @brief A class to manage all the game's events
class EventManager
{
public:

	void	Add(Event::pointer & e) { eq.push(e); }
	void	Process();

private:
	std::priority_queue<Event::pointer, std::deque<Event::pointer>, TimedEventComp> eq;
};




namespace global
{
// The global event queue
//extern std::queue<Event> EventQueue;
// The global timed event queue
//extern std::priority_queue<TimedEvent *, std::vector<TimedEvent*>, TimedEventComp> TimedEventQueue;
}

#endif /* EVENTS_HPP */
